﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Decisions.HL7.Message;
using System.Runtime.Serialization;
using DecisionsFramework.Design.Properties;
using System.Reflection;
using Decisions.HL7.Generated.AbstractMessage;
using Decisions.HL7.Parser;

namespace Decisions.HL7.DataTypes
{
    [DataContract]
    public abstract class AbstractMessage : AbstractHL7ParseableEntity
    {
        private ZSegment[] zSegments;

        public AbstractMessage()
        {
            if (mshSegment == null)
            {
                mshSegment = new MSH();
                SetValuesOnMSH();
            }
        }

        private void SetValuesOnMSH()
        {
            SetValuesOnMSH(null);
        }

        public void SetValuesOnMSH(HL7ParserOptions options)
        {
            if (mshSegment == null)
            {
                mshSegment = new MSH();
            }
            mshSegment.EncodingCharacters = HL7ParserConstants.DEFAULT_ENCODING_CHARS;
            mshSegment.FieldSeparator = new string(HL7ParserConstants.DEFAULT_FIELD_SEP, 1);
            if (string.IsNullOrEmpty(mshSegment.MessageControlID))
            {
                mshSegment.MessageControlID = MSHDataGeneratorRegistry.Generator.GetNextControlId();
            }
            if (mshSegment.SendingFacility == null || string.IsNullOrEmpty(mshSegment.SendingFacility.NamespaceID) == true)
            {
                mshSegment.SendingFacility = new HD() { NamespaceID = MSHDataGeneratorRegistry.Generator.GetSendingFacility() };
            }
            if (mshSegment.DateTimeofMessage == null)
            {
                mshSegment.DateTimeofMessage = new DTM() { Value = DateTime.Now };
            }


            if (options != null)
            {

                mshSegment.VersionID = new VID() { VersionID = HL7VersionUtil.GetVersionText(options.Version) }; // Default all outbound to 2.7 and let interface override.

                mshSegment.EncodingCharacters = options.GetEncodingChars();
                mshSegment.FieldSeparator = new string(options.FieldSep, 1);
            }
            else {
                mshSegment.VersionID = new VID() { VersionID = HL7VersionUtil.GetVersionText(HL7Version.v27) }; // Default all outbound to 2.7 and let interface override.
            }

        }

        private MSH mshSegment;

        // All hl7 messages have an msh.  it's non negotiable so it should 
        // be available right on the message.
        [DataMember]
        [PropertyClassification("MSH", 1)]
        public MSH MSH
        {
            get
            {
                // Ensure that the MSH always has major data elements in it.
                if (string.IsNullOrEmpty(mshSegment.EncodingCharacters) == true)
                {
                    SetValuesOnMSH();
                }

                return mshSegment;
            }
            set
            {
                if (value == null && mshSegment != null)
                {
                    // Log this and ignore.
                    return;
                }
                else
                {
                    mshSegment = value;
                }
            }
        }

        [DataMember]
        [PropertyClassification("Z Segments", 999)]
        public ZSegment[] ZSegments
        {
            get
            {
                return zSegments;
            }
            set
            {
                zSegments = value;
            }
        }

        #region Parser Helpers

        internal abstract Stack<string> ConsumeTextSegments(Stack<string> availableData, HL7ParserOptions options);

        #endregion

        internal string GetER7()
        {
            // Get PArser Optiosn from MSH
            HL7ParserOptions options = new HL7ParserOptions(this);
            return GetER7(options);
        }

        internal string[] GetZSegmentsER7(HL7ParserOptions options)
        {
            List<string> zSegmentText = new List<string>();
            if (ZSegments != null && ZSegments.Length > 0)
            {
                foreach (ZSegment zSeg in ZSegments)
                {
                    zSegmentText.Add(zSeg.GetER7(options));
                }
            }
            return zSegmentText.ToArray();
        }

        internal void ConsumeZSegmentsFromText(Stack<string> availableData, HL7ParserOptions options)
        {
            List<ZSegment> myZSegments = new List<ZSegment>();
            if (availableData != null && availableData.Count > 0)
            {
                foreach (string eachPossibleZ in availableData)
                {
                    if (eachPossibleZ.StartsWith("Z", StringComparison.OrdinalIgnoreCase))
                    {
                        // This is a Z Segment!
                        string[] allParts = eachPossibleZ.Split(options.FieldSep);
                        ZSegment z = new ZSegment();
                        z.SegmentName = allParts[0];
                        if (allParts.Length > 1)
                            z.Value1 = allParts[1];
                        if (allParts.Length > 2)
                            z.Value2 = allParts[2];
                        if (allParts.Length > 3)
                            z.Value3 = allParts[3];
                        if (allParts.Length > 4)
                            z.Value4 = allParts[4];
                        if (allParts.Length > 5)
                            z.Value5 = allParts[5];
                        if (allParts.Length > 6)
                            z.Value6 = allParts[6];
                        if (allParts.Length > 7)
                            z.Value7 = allParts[7];
                        if (allParts.Length > 8)
                            z.Value8 = allParts[8];
                        if (allParts.Length > 9)
                            z.Value9 = allParts[9];
                        if (allParts.Length > 10)
                            z.Value10 = allParts[10];
                        if (allParts.Length > 11)
                            z.Value11 = allParts[11];
                        if (allParts.Length > 12)
                            z.Value12 = allParts[12];
                        if (allParts.Length > 13)
                            z.Value13 = allParts[13];
                        if (allParts.Length > 14)
                            z.Value14 = allParts[14];
                        if (allParts.Length > 15)
                            z.Value15 = allParts[15];
                        if (allParts.Length > 16)
                            z.Value16 = allParts[16];
                        if (allParts.Length > 17)
                            z.Value17 = allParts[17];
                        if (allParts.Length > 18)
                            z.Value18 = allParts[18];
                        if (allParts.Length > 19)
                            z.Value19 = allParts[19];
                        if (allParts.Length > 20)
                            z.Value20 = allParts[20];
                        if (allParts.Length > 21)
                        {
                            z.AdditionalData = allParts.Skip(21).ToArray();
                        }
                        myZSegments.Add(z);
                    }
                }
            }
            zSegments = myZSegments.ToArray();
        }


        [DataMember]
        public string WholeMessageAsER7Text
        {
            get
            {
                return GetER7();
            }
            set
            {
                return;
            }
        }

        [DataMember]
        public HL7Message MessageType { get; set; }

        [DataMember]
        public HL7Version Version { get; set; }

    }
}
